﻿/*
-----------------------------------------------------------------------------
This source file is part of Cell Cloud.

Copyright (c) 2009-2012 Cell Cloud Team (cellcloudproject@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "CellStableHeaders.h"
#include "CellFileExpress.h"
#include "CellFileExpressContext.h"
#include "CellFileExpressListener.h"
#include "CellFileExpressTask.h"
#include "CellFileAttribute.h"
#include "CellNonblockingAcceptor.h"
#include "CellMessage.h"
#include "CellPacket.h"
#include "CellLoggerManager.h"
#include "CellExecutorService.h"
#include "CellExecutorManager.h"
#include "CellStringConverter.h"
#include "CellString.h"
#include "CellUtil.h"
#include "CellFileUtil.h"

namespace cell
{

//---------------------------------------------------------------------------
FileExpress::FileExpress(void)
	: mAcceptor(NULL)
	, mExecutor(NULL)
	, mTaskListener(NULL)
{
	String name = "FileExpress_" + cell::peek(this);
	mExecutor = ExecutorManager::getSingleton().createCachedThreadPool(
		name, 8, 64);
	mExecutor->addListener(this);

	mReceiveCache = CELL_ALLOC_T(char, FE_CACHE_SIZE, MEMCATEGORY_GENERAL);
	memset(mReceiveCache, 0x0, FE_CACHE_SIZE);
}
//---------------------------------------------------------------------------
FileExpress::~FileExpress(void)
{
	{
		CELL_LOCK_MUTEX(mTaskMutex);

		ExpressTasks::iterator iter = mExpressTasks.begin(), end = mExpressTasks.end();
		while (iter != end)
		{
			FileExpressTask* task = (*iter);
			task->abort();

			++iter;
		}
	}

	while (!mExpressTasks.empty())
	{
		Thread::sleep(100);
	}

	if (NULL != mExecutor)
	{
		ExecutorManager::getSingleton().destroyCachedThreadPool(mExecutor->getName());
		mExecutor = NULL;
	}

	if (!mContexts.empty())
	{
		Contexts::iterator iter = mContexts.begin(), end = mContexts.end();
		while (iter != end)
		{
			CELL_DELETE iter->second;
			++iter;
		}

		mContexts.clear();
	}

	if (!mServoContexts.empty())
	{
		ServoContexts::iterator iter = mServoContexts.begin(), end = mServoContexts.end();
		while (iter != end)
		{
			CELL_DELETE iter->second;
			++iter;
		}
	}

	if (NULL != mTaskListener)
	{
		CELL_DELETE mTaskListener;
		mTaskListener = NULL;
	}

	CELL_FREE(mReceiveCache, MEMCATEGORY_GENERAL);
}
//---------------------------------------------------------------------------
void FileExpress::startServer(uint port)
{
#if CELL_DEBUG_MODE
	LoggerManager::getSingleton().log("Start file express server...");
#endif // CELL_DEBUG_MODE

	if (NULL == mAcceptor)
	{
		mAcceptor = CELL_NEW NonblockingAcceptor();

		char head[4] = {0x10, 0x04, 0x11, 0x24};
		char tail[4] = {0x11, 0x24, 0x10, 0x04};
		mAcceptor->defineDataMark(head, 4, tail, 4);

		// 设置最大连接数
		mAcceptor->setMaxConnectNum(32);

		// 设置处理器
		mAcceptor->setHandler(this);

		// 绑定服务端口
		mAcceptor->bind(port);
	}
}
//---------------------------------------------------------------------------
void FileExpress::stopServer(void)
{
#if CELL_DEBUG_MODE
	LoggerManager::getSingleton().log("Stop file express server...");
#endif // CELL_DEBUG_MODE

	if (NULL != mAcceptor)
	{
		mAcceptor->unbind();

		CELL_DELETE mAcceptor;
		mAcceptor = NULL;
	}

	{
		CELL_LOCK_MUTEX(mListenerMutex);
		mExpressListeners.clear();
	}

	if (NULL != mExecutor)
	{
		ExecutorManager::getSingleton().destroyCachedThreadPool(mExecutor->getName());
		mExecutor = NULL;
	}

	{
		CELL_LOCK_MUTEX(mContextMutex);

		if (!mServoContexts.empty())
		{
			ServoContexts::iterator iter = mServoContexts.begin(), end = mServoContexts.end();
			while (iter != end)
			{
				String fileName = iter->first;
				iter->second->closeFile(fileName);

				CELL_DELETE iter->second;
				++iter;
			}

			mServoContexts.clear();
		}
	}

	{
		CELL_LOCK_MUTEX(mAuthMutex);

		SessionRecords::iterator iter = mSessionRecords.begin(), end = mSessionRecords.end();
		while (iter != end)
		{
			CELL_DELETE iter->second;
			++iter;
		}

		mSessionRecords.clear();
	}
}
//---------------------------------------------------------------------------
void FileExpress::addAuthCode(const ExpressAuthCode& code)
{
	CELL_LOCK_MUTEX(mAuthMutex);

	ExpressAuthCodes::iterator iter = mAuthCodes.find(code.getCode());
	if (iter == mAuthCodes.end())
	{
		mAuthCodes.insert(ExpressAuthCodes::value_type(code.getCode(), code));
	}
}
//---------------------------------------------------------------------------
void FileExpress::removeAuthCode(const String& authCode)
{
	CELL_LOCK_MUTEX(mAuthMutex);

	ExpressAuthCodes::iterator iter = mAuthCodes.find(authCode);
	if (iter != mAuthCodes.end())
	{
		mAuthCodes.erase(iter);
	}
}
//---------------------------------------------------------------------------
bool FileExpress::download(const InetAddress* address, const String& fileName,
	const String& fileLocalPath, const String& authCode)
{
	// 检查文件名和路径名
	if (fileName.length() > FE_MAX_FILENAME || fileLocalPath.length() > FE_MAX_FILENAME)
	{
		// TODO 错误处理，文件名超长
		return false;
	}

	String localPath = fileLocalPath;
	if (!StringUtil::endsWith(localPath, "\\")
		&& !StringUtil::endsWith(localPath, "/"))
	{
		localPath += FileUtil::separator();
	}

	if (NULL == mTaskListener)
	{
		mTaskListener = CELL_NEW ExpressTaskListener(this);
	}

	// 创建上下文
	FileExpressContext* ctx = CELL_NEW FileExpressContext(authCode, address, fileName, localPath);

	// 创建任务
	FileExpressTask* task = CELL_NEW FileExpressTask(ctx);
	task->setListener(mTaskListener);

	if (mExecutor->execute(task))
	{
		{
			CELL_LOCK_MUTEX(mTaskMutex);

			mExpressTasks.push_back(task);
		}

		{
			CELL_LOCK_MUTEX(mContextMutex);

			mContexts.insert(Contexts::value_type(authCode, ctx));
		}

		return true;
	}
	else
	{
		// 启动执行失败
		CELL_DELETE task;
		CELL_DELETE ctx;

		return false;
	}
}
//---------------------------------------------------------------------------
bool FileExpress::upload(const InetAddress* address, const String& fullPath, const String& authCode)
{
	// 检查文件
	if (fullPath.length() > FE_MAX_FILENAME + FE_MAX_FILENAME)
	{
		// TODO 错误处理，文件名超长
		return false;
	}

	if (NULL == mTaskListener)
	{
		mTaskListener = CELL_NEW ExpressTaskListener(this);
	}

	// 创建上下文
	FileExpressContext* ctx = CELL_NEW FileExpressContext(authCode, address, fullPath);

	// 创建任务
	FileExpressTask* task = CELL_NEW FileExpressTask(ctx);
	task->setListener(mTaskListener);

	if (mExecutor->execute(task))
	{
		{
			CELL_LOCK_MUTEX(mTaskMutex);

			mExpressTasks.push_back(task);
		}

		{
			CELL_LOCK_MUTEX(mContextMutex);

			mContexts.insert(Contexts::value_type(authCode, ctx));
		}

		return true;
	}
	else
	{
		// 启动执行失败
		CELL_DELETE task;
		CELL_DELETE ctx;

		return false;
	}
}
//---------------------------------------------------------------------------
void FileExpress::abort(const String& authCode)
{
	CELL_LOCK_MUTEX(mTaskMutex);

	ExpressTasks::iterator iter = mExpressTasks.begin(), end = mExpressTasks.end();
	while (iter != end)
	{
		FileExpressTask* task = (*iter);
		if (task->getContext()->getAuthCode()->getCode() == authCode)
		{
			task->abort();
		}

		++iter;
	}
}
//---------------------------------------------------------------------------
void FileExpress::addListener(FileExpressListener* listener)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	ExpressListeners::iterator iter = std::find(mExpressListeners.begin(),
		mExpressListeners.end(), listener);
	if (iter == mExpressListeners.end())
	{
		mExpressListeners.push_back(listener);
	}
}
//---------------------------------------------------------------------------
void FileExpress::removeListener(FileExpressListener* listener)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	ExpressListeners::iterator iter = std::find(mExpressListeners.begin(),
		mExpressListeners.end(), listener);
	if (iter != mExpressListeners.end())
	{
		mExpressListeners.erase(iter);
	}
}
//---------------------------------------------------------------------------
bool FileExpress::hasTaskDone(const String& authCode)
{
	{
		CELL_LOCK_MUTEX(mContextMutex);

		Contexts::iterator iter = mContexts.find(authCode);
		if (iter != mContexts.end())
		{
			return false;
		}
	}

	return true;
}
//---------------------------------------------------------------------------
void FileExpress::maintainSevoContext(void)
{
	CELL_LOCK_MUTEX(mContextMutex);

	std::vector<String> list;
	ServoContexts::iterator iter = mServoContexts.begin(), end = mServoContexts.end();
	while (iter != end)
	{
		FileExpressServoContext* ctx = iter->second;
		if (ctx->getRemainingTime() <= 0)
		{
			list.push_back(iter->first);
		}

		++iter;
	}

	if (list.empty())
	{
		return;
	}

	std::vector<String>::iterator citer = list.begin(), cend = list.end();
	while (citer != cend)
	{
		iter = mServoContexts.find(*citer);
		FileExpressServoContext* ctx = iter->second;
		mServoContexts.erase(iter);
		CELL_DELETE ctx;

		++citer;
	}
}
//---------------------------------------------------------------------------
void FileExpress::interpret(Session* session, Packet* packet)
{
	char tag[5] = {0x0};
	packet->getTag(tag);

	if (tag[0] == FEPT_DATA_B1 && tag[1] == FEPT_DATA_B2
		&& tag[2] == FEPT_DATA_B3 && tag[3] == FEPT_DATA_B4)
	{
		responseData(session, packet);
	}
	else if (tag[0] == FEPT_DATA_RECEIPT_B1 && tag[1] == FEPT_DATA_RECEIPT_B2
		&& tag[2] == FEPT_DATA_RECEIPT_B3 && tag[3] == FEPT_DATA_RECEIPT_B4)
	{
		responseDataReceipt(session, packet);
	}
	else if (tag[0] == FEPT_BEGIN_B1 && tag[1] == FEPT_BEGIN_B2
		&& tag[2] == FEPT_BEGIN_B3 && tag[3] == FEPT_BEGIN_B4)
	{
		responseBegin(session, packet);
	}
	else if (tag[0] == FEPT_END_B1 && tag[1] == FEPT_END_B2
		&& tag[2] == FEPT_END_B3 && tag[3] == FEPT_END_B4)
	{
		responseEnd(session, packet);
	}
	else if (tag[0] == FEPT_OFFER_B1 && tag[1] == FEPT_OFFER_B2
		&& tag[2] == FEPT_OFFER_B3 && tag[3] == FEPT_OFFER_B4)
	{
		responseOffer(session, packet);
	}
	else if (tag[0] == FEPT_ATTR_B1 && tag[1] == FEPT_ATTR_B2
		&& tag[2] == FEPT_ATTR_B3 && tag[3] == FEPT_ATTR_B4)
	{
		responseAttribute(session, packet);
	}
	else if (tag[0] == FEPT_AUTH_B1 && tag[1] == FEPT_AUTH_B2
		&& tag[2] == FEPT_AUTH_B3 && tag[3] == FEPT_AUTH_B4)
	{
		authenticate(session, packet);
	}
}
//---------------------------------------------------------------------------
void FileExpress::authenticate(Session* session, Packet* packet)
{
	// 包格式：授权码

	char authCode[64] = {0x0};
	packet->getSubsegment(authCode, 0);

	bool auth = false;
	ExpressAuthCode code;

	{
		CELL_LOCK_MUTEX(mAuthMutex);

		ExpressAuthCodes::iterator iter = mAuthCodes.find(authCode);
		if (iter != mAuthCodes.end())
		{
			auth = true;
			code = iter->second;

			// 将 Session 标记为合法
			SessionRecord* record = NULL;
			SessionRecords::iterator iter = mSessionRecords.find(session->getId());
			if (iter != mSessionRecords.end())
			{
				record = iter->second;
			}
			else
			{
				record = CELL_NEW SessionRecord();
				mSessionRecords.insert(SessionRecords::value_type(session->getId(), record));
			}

			// 记录授权码
			record->addAuthCode(authCode);
		}
	}

	// 包格式：授权码能力描述

	char ptg[5] = {0x0};
	FEPT_AUTH_ASSIGN(ptg);
	Packet response(ptg, 1);

	if (auth)
	{
		// 添加上下文
		{
			CELL_LOCK_MUTEX(mContextMutex);

			ServoContexts::iterator iter = mServoContexts.find(authCode);
			if (iter == mServoContexts.end())
			{
				FileExpressServoContext* ctx = CELL_NEW FileExpressServoContext(code);
				mServoContexts.insert(ServoContexts::value_type(authCode, ctx));
			}
		}

		// 响应 - 允许传输文件
		char cap[FEA_DML] = {0x0};
		uint len = 0;
		switch (code.getAuth())
		{
		case ExpressAuthCode::WRITE:
			memcpy(cap, FEA_WRITE, FEA_WRITE_DL);
			len = FEA_WRITE_DL;
			break;
		case ExpressAuthCode::READ:
			memcpy(cap, FEA_READ, FEA_READ_DL);
			len = FEA_READ_DL;
			break;
		default:
			memcpy(cap, FEA_NOACCESS, FEA_NOACCESS_DL);
			len = FEA_NOACCESS_DL;
			break;
		}
		response.appendSubsegment(cap, len);
	}
	else
	{
		// 响应 - 不允许传输文件
		char cap[FEA_DML] = {0x0};
		memcpy(cap, FEA_NOACCESS, FEA_NOACCESS_DL);
		response.appendSubsegment(cap, FEA_NOACCESS_DL);
	}

	char data[512] = {0x0};
	uint datalen = Packet::pack(data, &response);
	Message message(data, datalen);
	session->write(&message);

	// 进行伺服上下文维护
	maintainSevoContext();
}
//---------------------------------------------------------------------------
void FileExpress::responseAttribute(Session* session, Packet* packet)
{
	// 包格式：授权码|文件名

	if (packet->getSubsegmentNum() != 2)
	{
		return;
	}

	char authCode[64] = {0x0};
	packet->getSubsegment(authCode, 0);

	// 验证 Session
	if (false == checkSession(session, authCode))
	{
		reject(session);
		return;
	}

	FileExpressServoContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mContextMutex);

		ServoContexts::iterator iter = mServoContexts.find(authCode);
		if (iter != mServoContexts.end())
		{
			// 已授权的操作
			ctx = iter->second;
		}
	}

	if (NULL != ctx)
	{
		char fileName[256] = {0x0};
		packet->getSubsegment(fileName, 1);

		// 加载文件
		ctx->loadFile(fileName);
		// 获取属性
		FileAttribute* attr = ctx->getAttribute(fileName);

		// 包格式：文件名|属性序列

		char ptg[5] = {0x0};
		FEPT_ATTR_ASSIGN(ptg);
		Packet response(ptg, 2);

		// 文件名
		response.appendSubsegment(fileName, strlen(fileName));

		char attrbuf[1024] = {0x0};
		int buflen = attr->serialize(attrbuf);
		// 属性序列
		response.appendSubsegment(attrbuf, buflen);

		char data[1024] = {0x0};
		uint len = Packet::pack(data, &response);
		Message message(data, len);
		session->write(&message);
	}
	else
	{
		reject(session);
	}
}
//---------------------------------------------------------------------------
void FileExpress::responseBegin(Session* session, Packet* packet)
{
	// 包格式：授权码|文件名|文件长度|操作

	if (packet->getSubsegmentNum() < 4)
	{
		return;
	}

	char authCode[64] = {0x0};
	packet->getSubsegment(authCode, 0);

	// 验证 Session
	if (false == checkSession(session, authCode))
	{
		reject(session);
		return;
	}

	FileExpressServoContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mContextMutex);

		ServoContexts::iterator iter = mServoContexts.find(authCode);
		if (iter != mServoContexts.end())
		{
			// 已授权的操作
			ctx = iter->second;
		}
	}

	if (NULL != ctx)
	{
		char filename[256] = {0x0};
		packet->getSubsegment(filename, 1);

		char szSize[32] = {0x0};
		packet->getSubsegment(szSize, 2);
		long fileSize = StringConverter::parseLong(szSize);

		char szOperate[4] = {0x0};
		packet->getSubsegment(szOperate, 3);
		int operate = StringConverter::parseInt(szOperate);

		if (operate == FileExpressContext::OP_UPLOAD)
		{
			// 准备文件
			ctx->prepareFile(filename, fileSize);
		}

		{
			// 记录文件传输
			CELL_LOCK_MUTEX(mAuthMutex);

			SessionRecords::iterator iter = mSessionRecords.find(session->getId());
			if (iter != mSessionRecords.end())
			{
				SessionRecord* record = iter->second;
				// 记录文件
				record->addFileName(filename);
			}
		}

		// 响应
		// 包格式：文件名|文件长度

		char ptag[5] = {0x0};
		FEPT_BEGIN_ASSIGN(ptag);
		Packet response(ptag, 3);
		response.appendSubsegment(filename, strlen(filename));
		response.appendSubsegment(szSize, strlen(szSize));

		char data[512] = {0x0};
		uint len = Packet::pack(data, &response);
		Message message(data, len);
		session->write(&message);

		// 回调
		FileExpressContext* context = ctx->getContext(filename);
		if (NULL != context)
		{
			context->setBytesTotal(fileSize);
			fireExpressStarted(context);
		}
	}
	else
	{
		reject(session);
	}
}
//---------------------------------------------------------------------------
void FileExpress::responseEnd(Session* session, Packet* packet)
{
	// 包结构：授权码|文件名|文件长度|操作

	if (packet->getSubsegmentNum() < 4)
	{
		return;
	}

	char authCode[64] = {0x0};
	packet->getSubsegment(authCode, 0);

	// 验证 Session
	if (false == checkSession(session, authCode))
	{
		reject(session);
		return;
	}

	char filename[256] = {0x0};
	packet->getSubsegment(filename, 1);

	char szOperate[4] = {0x0};
	packet->getSubsegment(szOperate, 3);
	int operate = StringConverter::parseInt(szOperate);

	FileExpressServoContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mContextMutex);

		ServoContexts::iterator iter = mServoContexts.find(authCode);
		if (iter != mServoContexts.end())
		{
			ctx = iter->second;
		}
	}

	if (NULL != ctx)
	{
		// 回调
		fireExpressCompleted(ctx->getContext(filename));

		// 关闭文件
		ctx->closeFile(filename);
	}

	if (operate == FileExpressContext::OP_UPLOAD)
	{
		char szSize[16] = {0x0};
		packet->getSubsegment(szSize, 2);

		// 包格式：文件名|文件长度
		// 响应
		char ptag[5] = {0x0};
		FEPT_END_ASSIGN(ptag);
		Packet response(ptag, 5);
		response.appendSubsegment(filename, strlen(filename));
		response.appendSubsegment(szSize, strlen(szSize));

		char data[512] = {0x0};
		uint len = Packet::pack(data, &response);
		Message message(data, len);
		session->write(&message);
	}

	{
		CELL_LOCK_MUTEX(mAuthMutex);

		SessionRecords::iterator iter = mSessionRecords.find(session->getId());
		if (iter != mSessionRecords.end())
		{
			SessionRecord* record = iter->second;
			record->removeFileName(filename);
		}
	}
}
//---------------------------------------------------------------------------
void FileExpress::responseOffer(Session* session, Packet* packet)
{
	// 包格式：授权码|文件名|文件操作起始位置

	if (packet->getSubsegmentNum() < 3)
	{
		return;
	}

	char authCode[64] = {0x0};
	packet->getSubsegment(authCode, 0);

	// 验证 Session
	if (false == checkSession(session, authCode))
	{
		reject(session);
		return;
	}

	FileExpressServoContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mContextMutex);

		ServoContexts::iterator iter = mServoContexts.find(authCode);
		if (iter != mServoContexts.end())
		{
			// 已授权的操作
			ctx = iter->second;
		}
	}

	if (NULL != ctx)
	{
		char filename[256] = {0x0};
		packet->getSubsegment(filename, 1);

		char szOffset[16] = {0x0};
		packet->getSubsegment(szOffset, 2);
		uint offset = StringConverter::parseUnsignedInt(szOffset);

		char data[FE_FILEDATA_SIZE] = {0x0};
		uint datalen = ctx->readFile(data, filename, offset, FE_FILEDATA_SIZE);

		uint end = offset + datalen;
		char szEnd[16] = {0x0};
		sprintf(szEnd, "%u", end);

		// 包格式：授权码|文件名|数据起始位|数据结束位|数据

		char ptag[5] = {0x0};
		FEPT_DATA_ASSIGN(ptag);

		Packet response(ptag, 4);
		response.appendSubsegment(authCode, strlen(authCode));
		response.appendSubsegment(filename, strlen(filename));
		response.appendSubsegment(szOffset, strlen(szOffset));
		response.appendSubsegment(szEnd, strlen(szEnd));
		response.appendSubsegment(data, datalen);

		char pdata[FE_CACHE_SIZE] = {0x0};
		uint plen = Packet::pack(pdata, &response);
		Message message(pdata, plen);
		session->write(&message);
	}
	else
	{
		reject(session);
	}
}
//---------------------------------------------------------------------------
void FileExpress::responseData(Session* session, Packet* packet)
{
	// 包格式：授权码|文件名|数据起始位|数据结束位|数据

	if (packet->getSubsegmentNum() != 5)
	{
		return;
	}

	char authCode[64] = {0x0};
	packet->getSubsegment(authCode, 0);

	// 验证 Session
	if (false == checkSession(session, authCode))
	{
		reject(session);
		return;
	}

	FileExpressServoContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mContextMutex);

		ServoContexts::iterator iter = mServoContexts.find(authCode);
		if (iter != mServoContexts.end())
		{
			// 已授权的操作
			ctx = iter->second;
		}
	}

	if (NULL != ctx)
	{
		char filename[256] = {0x0};
		packet->getSubsegment(filename, 1);

		char szStart[32] = {0x0};
		packet->getSubsegment(szStart, 2);
		char szEnd[32] = {0x0};
		packet->getSubsegment(szEnd, 3);

		uint start = StringConverter::parseUnsignedInt(szStart);
		uint end = StringConverter::parseUnsignedInt(szEnd);

		char data[FE_FILEDATA_SIZE] = {0x0};
		packet->getSubsegment(data, 4);

		// 保存数据
		ctx->writeFile(filename, data, start, end - start);

		// 响应
		// 包格式：文件名|数据进度

		char ptag[5] = {0x0};
		FEPT_DATA_RECEIPT_ASSIGN(ptag);
		Packet response(ptag, 4);
		response.appendSubsegment(filename, strlen(filename));
		response.appendSubsegment(szEnd, strlen(szEnd));

		char pdata[512] = {0x0};
		uint len = Packet::pack(pdata, &response);
		Message message(pdata, len);
		session->write(&message);

		// 回调
		FileExpressContext* context = ctx->getContext(filename);
		if (NULL != context)
		{
			context->setBytesLoaded(end);
			fireExpressProgress(context);
		}
	}
	else
	{
		reject(session);
	}
}
//---------------------------------------------------------------------------
void FileExpress::responseDataReceipt(Session* session, Packet* packet)
{
	// 包格式：授权码|文件名|新数据进度

	if (packet->getSubsegmentNum() < 3)
	{
		return;
	}

	char authCode[64] = {0x0};
	packet->getSubsegment(authCode, 0);

	// 验证 Session
	if (false == checkSession(session, authCode))
	{
		reject(session);
		return;
	}

	FileExpressServoContext* ctx = NULL;

	{
		CELL_LOCK_MUTEX(mContextMutex);

		ServoContexts::iterator iter = mServoContexts.find(authCode);
		if (iter != mServoContexts.end())
		{
			// 已授权的操作
			ctx = iter->second;
		}
	}

	if (NULL != ctx)
	{
		char filename[256] = {0x0};
		packet->getSubsegment(filename, 1);

		char szOffset[16] = {0x0};
		packet->getSubsegment(szOffset, 2);
		uint offset = StringConverter::parseUnsignedInt(szOffset);

		char data[FE_FILEDATA_SIZE] = {0x0};
		uint datalen = ctx->readFile(data, filename, offset, FE_FILEDATA_SIZE);
		if (datalen > 0)
		{
			uint end = offset + datalen;
			char szEnd[16] = {0x0};
			sprintf(szEnd, "%u", end);

			// 包格式：授权码|文件名|数据起始位|数据结束位|数据

			char ptag[5] = {0x0};
			FEPT_DATA_ASSIGN(ptag);

			Packet response(ptag, 4);
			response.appendSubsegment(authCode, strlen(authCode));
			response.appendSubsegment(filename, strlen(filename));
			response.appendSubsegment(szOffset, strlen(szOffset));
			response.appendSubsegment(szEnd, strlen(szEnd));
			response.appendSubsegment(data, datalen);

			char pdata[FE_CACHE_SIZE] = {0x0};
			uint plen = Packet::pack(pdata, &response);
			Message message(pdata, plen);
			session->write(&message);

			FileExpressContext* context = ctx->getContext(filename);
			if (NULL != context)
			{
				context->setBytesLoaded(offset + datalen);
				fireExpressProgress(context);
			}
		}
		else
		{
			// 文件数据发送完毕

			char szSize[16] = {0x0};
			sprintf(szSize, "%ld", ctx->getAttribute(filename)->size());

			// 包格式：文件名|文件长度
			// 响应
			char ptag[5] = {0x0};
			FEPT_END_ASSIGN(ptag);
			Packet response(ptag, 5);
			response.appendSubsegment(filename, strlen(filename));
			response.appendSubsegment(szSize, strlen(szSize));

			char data[512] = {0x0};
			uint len = Packet::pack(data, &response);
			Message message(data, len);
			session->write(&message);
		}
	}
}
//---------------------------------------------------------------------------
bool FileExpress::checkSession(Session* session, const String& authCode)
{
	CELL_LOCK_MUTEX(mAuthMutex);

	SessionRecords::iterator iter = mSessionRecords.find(session->getId());
	if (iter != mSessionRecords.end())
	{
		if (iter->second->containsAuthCode(authCode))
			return true;
		else
			return false;
	}
	else
	{
		return false;
	}
}
//---------------------------------------------------------------------------
void FileExpress::reject(Session* session)
{
	char ptag[5] = {0x0};
	FEPT_REJECT_ASSIGN(ptag);

	Packet packet(ptag, 10);

	char data[256] = {0x0};
	uint len = Packet::pack(data, &packet);
	if (len > 0)
	{
		Message message(data, len);
		session->write(&message);
	}
}
//---------------------------------------------------------------------------
void FileExpress::interrupt(Session* session)
{
	SessionRecord* record = NULL;

	{
		CELL_LOCK_MUTEX(mAuthMutex);

		SessionRecords::iterator iter = mSessionRecords.find(session->getId());
		if (iter == mSessionRecords.end())
		{
			return;
		}

		record = iter->second;
		mSessionRecords.erase(iter);
	}

	{
		CELL_LOCK_MUTEX(mContextMutex);

		// 遍历所有的授权码
		StringVector::const_iterator aciter = record->getAuthCodeList().begin(),
			acend = record->getAuthCodeList().end();
		while (aciter != acend)
		{
			// 授权码
			String authCode = (*aciter);

			// 根据授权码查找到上下文
			ServoContexts::iterator iter = mServoContexts.find(authCode);
			if (iter != mServoContexts.end())
			{
				// 服务上下文
				FileExpressServoContext* ctx = iter->second;
				
				// 关闭上下文里的文件
				StringVector::const_iterator fniter = record->getFileNameList().begin(),
					fnend = record->getFileNameList().end();
				while (fniter != fnend)
				{
					// 通知事件
					fireExpressError(ctx->getContext(*fniter));

					// 关闭文件
					ctx->closeFile(*fniter);
					++fniter;
				}
			}

			++aciter;
		}
	}

	CELL_DELETE record;
}
//---------------------------------------------------------------------------
void FileExpress::fireExpressStarted(FileExpressContext* ctx)
{
	if (NULL == ctx)
		return;

	CELL_LOCK_MUTEX(mListenerMutex);

	FileExpress::ExpressListeners::iterator iter = mExpressListeners.begin(),
		end = mExpressListeners.end();
	while (iter != end)
	{
		(*iter)->expressStarted(ctx);
		++iter;
	}
}
//---------------------------------------------------------------------------
void FileExpress::fireExpressCompleted(FileExpressContext* ctx)
{
	if (NULL == ctx)
		return;

	CELL_LOCK_MUTEX(mListenerMutex);

	FileExpress::ExpressListeners::iterator iter = mExpressListeners.begin(),
		end = mExpressListeners.end();
	while (iter != end)
	{
		(*iter)->expressCompleted(ctx);
		++iter;
	}
}
//---------------------------------------------------------------------------
void FileExpress::fireExpressProgress(FileExpressContext* ctx)
{
	if (NULL == ctx)
		return;

	CELL_LOCK_MUTEX(mListenerMutex);

	FileExpress::ExpressListeners::iterator iter = mExpressListeners.begin(),
		end = mExpressListeners.end();
	while (iter != end)
	{
		(*iter)->expressProgress(ctx);
		++iter;
	}
}
//---------------------------------------------------------------------------
void FileExpress::fireExpressError(FileExpressContext* ctx)
{
	CELL_LOCK_MUTEX(mListenerMutex);

	FileExpress::ExpressListeners::iterator iter = mExpressListeners.begin(),
		end = mExpressListeners.end();
	while (iter != end)
	{
		(*iter)->expressError(ctx);
		++iter;
	}
}
//---------------------------------------------------------------------------
void FileExpress::sessionCreated(Session* session)
{
}
//---------------------------------------------------------------------------
void FileExpress::sessionDestroyed(Session* session)
{
	interrupt(session);
}
//---------------------------------------------------------------------------
void FileExpress::sessionOpened(Session* session)
{
}
//---------------------------------------------------------------------------
void FileExpress::sessionClosed(Session* session)
{
	interrupt(session);
}
//---------------------------------------------------------------------------
void FileExpress::messageReceived(Session* session, Message* message)
{
	memset(mReceiveCache, 0x0, FE_CACHE_SIZE);
	uint32 len = message->get(mReceiveCache);

	Packet packet;
	if (Packet::unpack(&packet, mReceiveCache, len))
	{
		interpret(session, &packet);
	}
}
//---------------------------------------------------------------------------
void FileExpress::messageSent(Session* session, Message* message)
{

}
//---------------------------------------------------------------------------
void FileExpress::errorOccurred(uint16 errorCode, Session* session)
{

}
//---------------------------------------------------------------------------
void FileExpress::prepared(Runnable* command)
{
}
//---------------------------------------------------------------------------
void FileExpress::executed(Runnable* command)
{
	FileExpressTask* task = dynamic_cast<FileExpressTask*>(command);

	{
		CELL_LOCK_MUTEX(mTaskMutex);

		ExpressTasks::iterator iter = std::find(mExpressTasks.begin(),
				mExpressTasks.end(), task);
		if (iter != mExpressTasks.end())
		{
			mExpressTasks.erase(iter);
		}
	}

	{
		CELL_LOCK_MUTEX(mContextMutex);

		Contexts::iterator iter = mContexts.find(task->getContext()->getAuthCode()->getCode());
		if (iter != mContexts.end())
		{
			FileExpressContext* ctx = iter->second;
			mContexts.erase(iter);

			CELL_DELETE ctx;
		}
	}

	CELL_DELETE task;
}



//---------------------------------------------------------------------------
FileExpress::SessionRecord::SessionRecord(void)
{
}
FileExpress::SessionRecord::SessionRecord(const SessionRecord& other)
{
}
//---------------------------------------------------------------------------
FileExpress::SessionRecord::~SessionRecord(void)
{
}
//---------------------------------------------------------------------------
void FileExpress::SessionRecord::addAuthCode(const String& authCode)
{
	StringVector::iterator iter = std::find(mAuthCodes.begin(), mAuthCodes.end(), authCode);
	if (iter == mAuthCodes.end())
	{
		mAuthCodes.push_back(authCode);
	}
}
//---------------------------------------------------------------------------
void FileExpress::SessionRecord::removeAuthCode(const String& authCode)
{
	StringVector::iterator iter = std::find(mAuthCodes.begin(), mAuthCodes.end(), authCode);
	if (iter != mAuthCodes.end())
	{
		mAuthCodes.erase(iter);
	}
}
//---------------------------------------------------------------------------
void FileExpress::SessionRecord::addFileName(const String& fileName)
{
	StringVector::iterator iter = std::find(mFileNames.begin(), mFileNames.end(), fileName);
	if (iter == mFileNames.end())
	{
		mFileNames.push_back(fileName);
	}
}
//---------------------------------------------------------------------------
void FileExpress::SessionRecord::removeFileName(const String& fileName)
{
	StringVector::iterator iter = std::find(mFileNames.begin(), mFileNames.end(), fileName);
	if (iter != mFileNames.end())
	{
		mFileNames.erase(iter);
	}
}
//---------------------------------------------------------------------------
bool FileExpress::SessionRecord::containsAuthCode(const String& authCode)
{
	StringVector::iterator iter = std::find(mAuthCodes.begin(), mAuthCodes.end(), authCode);
	if (iter != mAuthCodes.end())
	{
		return true;
	}

	return false;
}
//---------------------------------------------------------------------------
const StringVector& FileExpress::SessionRecord::getAuthCodeList(void) const
{
	return mAuthCodes;
}
//---------------------------------------------------------------------------
const StringVector& FileExpress::SessionRecord::getFileNameList(void) const
{
	return mFileNames;
}


//---------------------------------------------------------------------------
const int ExpressAuthCode::DURATION_NONE = 0;

//---------------------------------------------------------------------------
ExpressAuthCode::ExpressAuthCode(void)
	: mOrigin(0)
	, mDuration(0)
	, mAuth(ExpressAuthCode::NO_ACCESS)
{
}
//---------------------------------------------------------------------------
ExpressAuthCode::ExpressAuthCode(const String& path, int auth, uint64 duration)
	: mOrigin(0)
	, mDuration(duration)
	, mAuth(auth)
{
	ulong code = Util::hashString(Util::randomString(4));
	uint64 time = Util::currentTimeMillis();
	mCode = StringConverter::toString((ulong)(time - code));

	mOrigin = time;

	setContextPath(path);
}
//---------------------------------------------------------------------------
ExpressAuthCode::ExpressAuthCode(const ExpressAuthCode& other)
	: mOrigin(other.mOrigin)
	, mDuration(other.mDuration)
	, mCode(other.mCode)
	, mContextPath(other.mContextPath)
	, mAuth(other.mAuth)
{
}
//---------------------------------------------------------------------------
ExpressAuthCode::~ExpressAuthCode(void)
{
}
//---------------------------------------------------------------------------
bool ExpressAuthCode::operator==(ExpressAuthCode& other) const
{
	return (mCode == other.mCode);
}
//---------------------------------------------------------------------------
bool ExpressAuthCode::operator==(const ExpressAuthCode& other) const
{
	return (mCode == other.mCode);
}
//---------------------------------------------------------------------------
ExpressAuthCode& ExpressAuthCode::operator=(ExpressAuthCode& other)
{
	mOrigin = other.mOrigin;
	mDuration = other.mDuration;
	mCode = other.mCode;
	mContextPath = other.mContextPath;
	mAuth = other.mAuth;
	return *this;
}
//---------------------------------------------------------------------------
const String& ExpressAuthCode::getCode(void) const
{
	return mCode;
}
//---------------------------------------------------------------------------
const String& ExpressAuthCode::getContextPath(void) const
{
	return mContextPath;
}
//---------------------------------------------------------------------------
int ExpressAuthCode::getAuth(void) const
{
	return mAuth;
}
//---------------------------------------------------------------------------
uint64 ExpressAuthCode::getDuration(void) const
{
	return mDuration;
}
//---------------------------------------------------------------------------
void ExpressAuthCode::setCode(const String& code)
{
	mCode = code;
}
//---------------------------------------------------------------------------
void ExpressAuthCode::setContextPath(const String& path)
{
	mContextPath = path;
	if (!StringUtil::endsWith(mContextPath, "\\")
		&& !StringUtil::endsWith(mContextPath, "/"))
	{
		mContextPath += FileUtil::separator();
	}
}
//---------------------------------------------------------------------------
void ExpressAuthCode::changeAuth(const char* auth) const
{
	if (strcmp(auth, FEA_WRITE) == 0)
	{
		mAuth = ExpressAuthCode::WRITE;
	}
	else if (strcmp(auth, FEA_READ) == 0)
	{
		mAuth = ExpressAuthCode::READ;
	}
	else
	{
		mAuth = ExpressAuthCode::NO_ACCESS;
	}
}



//---------------------------------------------------------------------------
ExpressTaskListener::ExpressTaskListener(FileExpress* express)
	: mExpress(express)
{
}
//---------------------------------------------------------------------------
ExpressTaskListener::~ExpressTaskListener(void)
{
}
//---------------------------------------------------------------------------
void ExpressTaskListener::expressStarted(FileExpressContext* context)
{
	CELL_LOCK_MUTEX(mExpress->mListenerMutex);

	FileExpress::ExpressListeners::iterator iter = mExpress->mExpressListeners.begin(),
		end = mExpress->mExpressListeners.end();
	while (iter != end)
	{
		(*iter)->expressStarted(context);
		++iter;
	}
}
//---------------------------------------------------------------------------
void ExpressTaskListener::expressCompleted(FileExpressContext* context)
{
	CELL_LOCK_MUTEX(mExpress->mListenerMutex);

	FileExpress::ExpressListeners::iterator iter = mExpress->mExpressListeners.begin(),
		end = mExpress->mExpressListeners.end();
	while (iter != end)
	{
		(*iter)->expressCompleted(context);
		++iter;
	}
}
//---------------------------------------------------------------------------
void ExpressTaskListener::expressProgress(FileExpressContext* context)
{
	CELL_LOCK_MUTEX(mExpress->mListenerMutex);

	FileExpress::ExpressListeners::iterator iter = mExpress->mExpressListeners.begin(),
		end = mExpress->mExpressListeners.end();
	while (iter != end)
	{
		(*iter)->expressProgress(context);
		++iter;
	}
}
//---------------------------------------------------------------------------
void ExpressTaskListener::expressError(FileExpressContext* context)
{
	CELL_LOCK_MUTEX(mExpress->mListenerMutex);

	FileExpress::ExpressListeners::iterator iter = mExpress->mExpressListeners.begin(),
		end = mExpress->mExpressListeners.end();
	while (iter != end)
	{
		(*iter)->expressError(context);
		++iter;
	}
}

} // end namespace cell
